﻿using System;
using System.Collections.Generic;

#region 观察者与被观察者接口
/// <summary>
/// 观察者接口：所有需要响应数据变化的类需实现此接口
/// </summary>
public interface IObserver
{
    // 数据更新时调用的方法，参数为最新的气象数据
    void Update(WeatherData data);
}

/// <summary>
/// 被观察者接口：气象站需实现此接口以管理观察者
/// </summary>
public interface ISubject
{
    void RegisterObserver(IObserver observer);   // 注册观察者
    void RemoveObserver(IObserver observer);     // 移除观察者
    void NotifyObservers();                      // 通知所有观察者
}

/// <summary>
/// 气象数据实体：封装需要传递的气象信息
/// </summary>
public class WeatherData
{
    public DateTime LastCollectTime { get; set; } // 最后采集时间
    public double Temperature { get; set; }       // 温度（℃）
    public double Humidity { get; set; }          // 湿度（%）
}
#endregion

#region 气象站类（被观察者）
/// <summary>
/// 气象站类：实现被观察者接口，维护气象数据并通知观察者
/// </summary>
public class WeatherStation : ISubject
{
    private List<IObserver> _observers; // 观察者列表
    private WeatherData _currentData;   // 当前气象数据

    public WeatherStation()
    {
        _observers = new List<IObserver>();
        _currentData = new WeatherData();
    }

    // 注册观察者
    public void RegisterObserver(IObserver observer)
    {
        if (!_observers.Contains(observer))
        {
            _observers.Add(observer);
        }
    }

    // 移除观察者
    public void RemoveObserver(IObserver observer)
    {
        if (_observers.Contains(observer))
        {
            _observers.Remove(observer);
        }
    }

    // 通知所有观察者（数据更新时调用）
    public void NotifyObservers()
    {
        foreach (var observer in _observers)
        {
            observer.Update(_currentData); // 传递最新数据
        }
    }

    /// <summary>
    /// 模拟气象数据更新（实际场景中可能是传感器采集）
    /// </summary>
    public void UpdateWeatherData(double temperature, double humidity)
    {
        // 更新数据
        _currentData.LastCollectTime = DateTime.Now;
        _currentData.Temperature = temperature;
        _currentData.Humidity = humidity;

        // 数据更新后自动通知所有观察者
        NotifyObservers();
    }
}
#endregion

#region 观察者实现类
/// <summary>
/// 屏幕显示类：实现观察者接口，负责更新屏幕显示
/// </summary>
public class ScreenDisplay : IObserver
{
    public void Update(WeatherData data)
    {
        Console.WriteLine("\n=== 屏幕显示更新 ===");
        Console.WriteLine($"最后采集时间：{data.LastCollectTime:yyyy-MM-dd HH:mm:ss}");
        Console.WriteLine($"温度：{data.Temperature} ℃");
        Console.WriteLine($"湿度：{data.Humidity} %");
        Console.WriteLine("====================");
    }
}

/// <summary>
/// 数据库保存类：实现观察者接口，负责保存数据到数据库
/// </summary>
public class DatabaseSaver : IObserver
{
    // 模拟数据库连接（实际项目中可替换为真实数据库操作）
    private string _connectionString = "Server=localhost;Database=WeatherDB;Uid=root;Pwd=123456;";

    public void Update(WeatherData data)
    {
        Console.WriteLine("\n=== 数据库保存操作 ===");
        Console.WriteLine($"连接数据库：{_connectionString}");
        Console.WriteLine($"保存数据：时间={data.LastCollectTime:yyyy-MM-dd HH:mm:ss}，温度={data.Temperature}，湿度={data.Humidity}");
        Console.WriteLine("数据保存成功！");
        Console.WriteLine("====================");
    }
}
#endregion

#region 测试程序
class Program
{
    static void Main(string[] args)
    {
        // 1. 创建气象站（被观察者）
        WeatherStation station = new WeatherStation();

        // 2. 创建观察者（屏幕显示、数据库保存）
        IObserver screen = new ScreenDisplay();
        IObserver dbSaver = new DatabaseSaver();

        // 3. 注册观察者到气象站
        station.RegisterObserver(screen);
        station.RegisterObserver(dbSaver);

        // 4. 模拟气象数据更新（触发自动通知）
        Console.WriteLine("=== 第一次采集数据 ===");
        station.UpdateWeatherData(25.5, 60.2); // 温度25.5℃，湿度60.2%

        // 等待1秒，模拟时间间隔
        System.Threading.Thread.Sleep(1000);

        Console.WriteLine("\n=== 第二次采集数据 ===");
        station.UpdateWeatherData(26.1, 58.7); // 温度26.1℃，湿度58.7%

        // 移除屏幕显示观察者
        station.RemoveObserver(screen);
        Console.WriteLine("\n=== 移除屏幕显示观察者后，第三次采集数据 ===");
        station.UpdateWeatherData(24.8, 62.3); // 仅数据库保存会响应
    }
}
#endregion